package com.chezai.client.activitys;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.baidu.aip.face.FaceRoundView;
import com.baidu.aip.face.stat.Ast;
import com.baidu.idl.face.platform.FaceConfig;
import com.baidu.idl.face.platform.FaceEnvironment;
import com.baidu.idl.face.platform.FaceSDKManager;
import com.baidu.idl.face.platform.FaceStatusEnum;
import com.baidu.idl.face.platform.IDetectStrategy;
import com.baidu.idl.face.platform.IDetectStrategyCallback;
import com.baidu.idl.face.platform.ui.FaceSDKResSettings;
import com.baidu.idl.face.platform.ui.utils.CameraUtils;
import com.baidu.idl.face.platform.utils.CameraPreviewUtils;
import com.chezai.client.R;
import com.chezai.client.bean.TakePhotoEntity;
import com.chezai.client.global.Config;
import com.chezai.client.global.Const;
import com.chezai.client.global.TerminalApplication;
import com.chezai.client.inter.ICamera2View;
import com.chezai.client.presenter.Camera2Presenter;
import com.chezai.client.utils.AppManager;
import com.chezai.client.utils.CameraMgr;
import com.chezai.client.utils.PreferenceManager;
import com.chezai.client.utils.SDCardUtil;
import com.chezai.client.utils.ToastUtil;

import org.greenrobot.eventbus.EventBus;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import butterknife.BindView;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

/**
 * 人脸采集接口
 * Created by likunyang on 2018/1/26.
 */

public class Camera2Activity extends BaseActivity<Camera2Presenter, ICamera2View> implements ICamera2View,
        SurfaceHolder.Callback,
        Camera.PreviewCallback,
        Camera.ErrorCallback,
        IDetectStrategyCallback, Camera.PictureCallback {

    // View
    @BindView(R.id.detect_root_layout)
    protected RelativeLayout mRootView;
    @BindView(R.id.detect_face_round)
    protected FaceRoundView rectView;
    @BindView(R.id.detect_top_tips)
    protected TextView mTipsTopView;
    @BindView(R.id.detect_bottom_tips)
    protected TextView mTipsBottomView;
    @BindView(R.id.surfaceView)
    protected SurfaceView mSurfaceView;
    protected SurfaceHolder mSurfaceHolder;
    // 人脸信息
    protected IDetectStrategy mIDetectStrategy;
    protected int mDisplayWidth = 0;
    protected int mDisplayHeight = 0;
    protected int mSurfaceWidth = 0;
    protected int mSurfaceHeight = 0;
    protected Drawable mTipsIcon;
    // 状态标识
    protected HashMap<String, String> mBase64ImageMap = new HashMap<>();
    protected boolean mIsCreateSurface = false;
    protected volatile boolean mIsCompletion = false;
    // 相机
    protected Camera mCamera;
    protected Camera.Parameters mCameraParam;
    protected int mPreviewWidth;
    protected int mPreviewHeight;
    protected int mPreviewDegree;
    @BindView(R.id.detect_result_image_layout)
    LinearLayout mImageLayout;
    // 显示Size
    private Rect mPreviewRect = new Rect();
    private int mPhotoEventType;
    private int trainPart;
    private String studentName;
    private String coachName;
    private long mClassRecordId;
    private String photoPath;
    private String uid;
    private boolean isTakeSucess;
    private int mRetryCount = 0;
    private Rect mDetectRect;
    private boolean isOpenVerity;
    private Bitmap bitmap;
    private Bitmap copyBitmap;
    private Disposable mDisposable;

    public static void startFaceCamera(Activity from, String uid, int photoEventType
            , int trainPart
            , String studentName
            , String coachName
            , Long classRecordId) {
        if (AppManager.getAppManager().isOpenActivity(Camera2Activity.class)) return;
        Intent intent = new Intent(from, Camera2Activity.class);
        intent.putExtra(Const.EVENT_PHOTO_TYPE, photoEventType);
        intent.putExtra(Const.TRAIN_PART, trainPart);
        intent.putExtra(Const.STUDENT_UID, uid);
        if (!TextUtils.isEmpty(studentName)) {
            intent.putExtra(Const.STUDENT_NAME, studentName);
        }
        if (!TextUtils.isEmpty(coachName)) {
            intent.putExtra(Const.COACH_NAME, coachName);
        }
        if (classRecordId != null) {
            intent.putExtra(Const.CLASS_RECORD_ID, classRecordId);
        }
        from.startActivity(intent);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FaceSDKResSettings.initializeResId();
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        if (mBase64ImageMap != null) {
            mBase64ImageMap.clear();
        }
        // harisucici 人脸超时
        int timeout = 5;
        Observable.timer(timeout, TimeUnit.SECONDS)
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        mDisposable = d;
                    }

                    @Override
                    public void onNext(Long aLong) {
                        if (mDisposable != null && !mDisposable.isDisposed() && mCamera != null) {
                            mCamera.takePicture(null, null, Camera2Activity.this);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mIDetectStrategy != null) {
            mIDetectStrategy.reset();
        }
        if (bitmap != null) {
            bitmap.recycle();// 回收bitmap空间
        }
        if (copyBitmap != null) {
            copyBitmap.recycle();
        }
        stopPreview();
        Ast.getInstance().immediatelyUpload();
    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_face_detect;
    }

    @Override
    public void initView(Bundle savedInstanceState) {
        initFace();
        DisplayMetrics dm = new DisplayMetrics();
        Display display = this.getWindowManager().getDefaultDisplay();
        display.getMetrics(dm);
        mDisplayWidth = dm.widthPixels;
        mDisplayHeight = dm.heightPixels;
        // harisucici 人脸提示关闭
        mTipsTopView.setVisibility(View.INVISIBLE);
    }

    private void initFace() {
        FaceSDKManager.getInstance().initialize(TerminalApplication.mContext, Config.licenseID, Config.licenseFileName);
        FaceConfig config = FaceSDKManager.getInstance().getFaceConfig();
        // 设置 活体动作是否随机 boolean
        config.setLivenessRandom(false);
        // 模糊度范围 (0-1) 推荐小于0.7
        config.setBlurnessValue(FaceEnvironment.VALUE_BLURNESS);
        // 光照范围 (0-1) 推荐大于40
        config.setBrightnessValue(FaceEnvironment.VALUE_BRIGHTNESS);
        // 裁剪人脸大小
        config.setCropFaceValue(FaceEnvironment.VALUE_CROP_FACE_SIZE);
        // 人脸yaw,pitch,row 角度，范围（-45，45），推荐-15-15
        config.setHeadPitchValue(FaceEnvironment.VALUE_HEAD_PITCH);
        config.setHeadRollValue(FaceEnvironment.VALUE_HEAD_ROLL);
        config.setHeadYawValue(FaceEnvironment.VALUE_HEAD_YAW);
        // 最小检测人脸（在图片人脸能够被检测到最小值）80-200， 越小越耗性能，推荐120-200
        config.setMinFaceSize(FaceEnvironment.VALUE_MIN_FACE_SIZE);
        // 人脸置信度（0-1）推荐大于0.6
        config.setNotFaceValue(FaceEnvironment.VALUE_NOT_FACE_THRESHOLD);
        // 人脸遮挡范围 （0-1） 推荐小于0.5
        config.setOcclusionValue(FaceEnvironment.VALUE_OCCLUSION);
        // 是否进行质量检测
        config.setCheckFaceQuality(true);
        // 人脸检测使用线程数
        config.setFaceDecodeNumberOfThreads(2);
        // 是否开启提示音
        config.setSound(false);
        FaceSDKManager.getInstance().setFaceConfig(config);
    }

    @Override
    public void initData() {
        isOpenVerity = PreferenceManager.getBoolean(Const.SP_IS_OPEN_VERITY, false);

//        isOpenVerity = true;// harisucici 人脸 打开试试
//        Ast.getInstance().init(getApplicationContext(), "3.1.0.0", "facenormal");
        Intent intent = getIntent();
        mPhotoEventType = intent.getIntExtra(Const.EVENT_PHOTO_TYPE, 0);
        trainPart = intent.getIntExtra(Const.TRAIN_PART, 0);
        if (intent.hasExtra(Const.STUDENT_NAME)) {
            studentName = intent.getStringExtra(Const.STUDENT_NAME);
        }
        if (intent.hasExtra(Const.COACH_NAME)) {
            coachName = intent.getStringExtra(Const.COACH_NAME);
        }
        if (intent.hasExtra(Const.CLASS_RECORD_ID)) {
            mClassRecordId = intent.getLongExtra(Const.CLASS_RECORD_ID, -1);
        }
        uid = intent.getStringExtra(Const.STUDENT_UID);
//        photoPath = SDCardUtil.getPhotoDir() + "" + DateUtil.timestampStr("yyMMddHHmm") + ".jpg";
        photoPath = SDCardUtil.getStudentPhotoPath();
    }

    protected void startPreview() {
        if (mSurfaceView != null && mSurfaceView.getHolder() != null) {
            mSurfaceHolder = mSurfaceView.getHolder();
            mSurfaceHolder.addCallback(this);
        }

        if (mCamera == null) {
            try {
                mCamera = Camera.open(Const.CameraChannel.FONT);
            } catch (RuntimeException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (mCamera == null) {
            return;
        }
        if (mCameraParam == null) {
            mCameraParam = mCamera.getParameters();
        }

        mCameraParam.setPictureFormat(PixelFormat.JPEG);
        int degree = CameraMgr.displayOrientation(Camera.CameraInfo.CAMERA_FACING_FRONT, this);
        mCamera.setDisplayOrientation(degree);
        // 设置后无效，camera.setDisplayOrientation方法有效
        mCameraParam.set("rotation", degree);
        mPreviewDegree = degree;
        if (mIDetectStrategy != null) {
            mIDetectStrategy.setPreviewDegree(degree);
        }
        Point point = CameraPreviewUtils.getBestPreview(mCameraParam,
                new Point(mDisplayWidth, mDisplayHeight));
        mPreviewWidth = point.x;
        mPreviewHeight = point.y;
        // Preview 768,432
        mPreviewRect.set(0, 0, mPreviewWidth, mPreviewHeight);
        mCameraParam.setPreviewSize(mPreviewWidth, mPreviewHeight);
        mCameraParam.setPictureSize(640, 480);
        if (mCameraParam.isAutoExposureLockSupported()) {
            mCameraParam.setAutoExposureLock(false);
        }
        if (mCameraParam.isAutoWhiteBalanceLockSupported()) {
            String whiteBalance = mCameraParam.getWhiteBalance();
            if (!TextUtils.equals(Camera.Parameters.WHITE_BALANCE_AUTO, whiteBalance)) {
                mCameraParam.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
            }
        }
        mCamera.setParameters(mCameraParam);

        try {
            mCamera.setPreviewDisplay(mSurfaceHolder);
            mCamera.stopPreview();
            mCamera.setErrorCallback(this);
            mCamera.setPreviewCallback(this);
            mCamera.startPreview();
        } catch (RuntimeException e) {
            e.printStackTrace();
            CameraUtils.releaseCamera(mCamera);
            mCamera = null;
        } catch (Exception e) {
            e.printStackTrace();
            CameraUtils.releaseCamera(mCamera);
            mCamera = null;
        }
    }

    protected void stopPreview() {
        if (mCamera != null) {
            try {
                mCamera.setErrorCallback(null);
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();
            } catch (RuntimeException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                CameraUtils.releaseCamera(mCamera);
                mCamera = null;
            }
        }
        if (mSurfaceHolder != null) {
            mSurfaceHolder.removeCallback(this);
        }
        if (mIDetectStrategy != null) {
            mIDetectStrategy = null;
        }
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mIsCreateSurface = true;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mSurfaceWidth = width;
        mSurfaceHeight = height;
        if (holder.getSurface() == null) {
            return;
        }
        startPreview();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mIsCreateSurface = false;
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {

        if (mIsCompletion) {
            return;
        }
        if (mIDetectStrategy == null && rectView != null && rectView.getRound() > 0) {
            mIDetectStrategy = FaceSDKManager.getInstance().getDetectStrategyModule();
            mIDetectStrategy.setPreviewDegree(mPreviewDegree);
            mIDetectStrategy.setDetectStrategySoundEnable(true);
            mDetectRect = FaceRoundView.getPreviewDetectRect(mSurfaceView.getWidth(), mPreviewWidth, mPreviewHeight);
            mIDetectStrategy.setDetectStrategyConfig(mPreviewRect, mDetectRect, this);
        }
        if (mIDetectStrategy != null) {
            mIDetectStrategy.detectStrategy(data);
        }
    }

    @Override
    public void onError(int error, Camera camera) {
        showToast("摄像头启动失败，请重试！");
        finish();
    }

    @Override
    public void onDetectCompletion(FaceStatusEnum status, String message, HashMap<String, String> base64ImageMap) {

        if (mIsCompletion) {
            return;
        }

        onRefreshView(status, message);
        if (status == FaceStatusEnum.OK) {
//            Ast.getInstance().faceHit();
            mIsCompletion = true;
            try {
                mCamera.takePicture(null, null, this);
            } catch (Exception e) {
                takePhotoFailed();
            }

        }
    }

    private void onRefreshView(FaceStatusEnum status, String message) {
        switch (status) {
            case OK:
                onRefreshTipsView(false, message);
                if (mTipsBottomView != null) mTipsBottomView.setText("");
                if (rectView != null) rectView.processDrawState(false);
                break;
            case Detect_PitchOutOfUpMaxRange:
            case Detect_PitchOutOfDownMaxRange:
            case Detect_PitchOutOfLeftMaxRange:
            case Detect_PitchOutOfRightMaxRange:
                onRefreshTipsView(true, message);
                if (mTipsBottomView != null) mTipsBottomView.setText(message);
                if (rectView != null) rectView.processDrawState(true);
                break;
            default:
                onRefreshTipsView(false, message);
                if (mTipsBottomView != null) mTipsBottomView.setText("");
                if (rectView != null) rectView.processDrawState(true);
        }
    }

    private void onRefreshTipsView(boolean isAlert, String message) {
        if (mTipsTopView != null) {
            if (isAlert) {
                if (mTipsIcon == null) {
                    mTipsIcon = getResources().getDrawable(R.mipmap.ic_warning);
                    mTipsIcon.setBounds(0, 0, (int) (mTipsIcon.getMinimumWidth() * 0.7f),
                            (int) (mTipsIcon.getMinimumHeight() * 0.7f));
                    mTipsTopView.setCompoundDrawablePadding(15);
                }
                mTipsTopView.setBackgroundResource(R.drawable.bg_tips);
                mTipsTopView.setText(R.string.detect_standard);
                mTipsTopView.setCompoundDrawables(mTipsIcon, null, null, null);
            } else {
                mTipsTopView.setBackgroundResource(R.drawable.bg_tips_no);
                mTipsTopView.setCompoundDrawables(null, null, null, null);
                if (!TextUtils.isEmpty(message)) {
                    mTipsTopView.setText(message);
                }
            }
        }
    }


    @Override
    public void finishView() {
        finish();
    }


    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
        Rect switchRect = CameraMgr.switchRect(mSurfaceView.getWidth(), mSurfaceView.getHeight(), bitmap.getWidth(), bitmap.getHeight(), rectView.getFaceRoundRect());
        copyBitmap = CameraMgr.copyBitmap(bitmap, switchRect);
        bitmap = CameraMgr.onWaterDraw(bitmap, trainPart, studentName, coachName, System.currentTimeMillis());
        isTakeSucess = CameraMgr.saveBitmapToFile(bitmap, photoPath);
        camera.stopPreview();// 关闭预览 处理数据
        if (isOpenVerity) {
            presenter.upload(copyBitmap, uid);
        } else {
            verifySucess();
        }
    }

    private void takePhotoFailed() {
        TakePhotoEntity takePhoto = new TakePhotoEntity();
        takePhoto.status = TakePhotoEntity.TAKE_PHOTO_FAILE;
        takePhoto.photoEventType = mPhotoEventType;
        EventBus.getDefault().postSticky(takePhoto);
        finish();
    }

    @Override
    public void verifySucess() {
        TakePhotoEntity takePhoto = new TakePhotoEntity();
        if (isTakeSucess) {
            takePhoto.status = TakePhotoEntity.TAKE_PHOTO_SUCESS;
            takePhoto.classRecordId = mClassRecordId;
            takePhoto.photoPath = photoPath;
            takePhoto.photoEventType = mPhotoEventType;
        } else {
            takePhoto.status = TakePhotoEntity.TAKE_PHOTO_FAILE;
        }
        EventBus.getDefault().postSticky(takePhoto);
        finish();
    }

    @Override
    public void verifyFailed(int errorCode) {
        if (errorCode == Camera2Presenter.VERIFY_ERROR_DEFAULT) {
            presenter.deletePhoto(photoPath);
            finish();
        } else if (errorCode == Camera2Presenter.VERIFY_ERROR_LOW) {
            if (mRetryCount >= 4) {
                ToastUtil.showLongToast(this, "重试次数已达上限,稍后重试");
                presenter.deletePhoto(photoPath);
                finish();
                return;
            }
            mRetryCount++;
            if (mIDetectStrategy != null) {
                mIDetectStrategy.reset();
                mIDetectStrategy = null;
            }
            startPreview();
            mIsCompletion = false;
        }

    }

    @Override
    public void getAccessToken() {
        if (isOpenVerity) {
            presenter.upload(copyBitmap, uid);
        } else {
            verifySucess();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mDisposable != null && !mDisposable.isDisposed()) {
            mDisposable.dispose();
        }
    }
}

